package com.zqll.gdx.starter.assets;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.assets.loaders.I18NBundleLoader;
import com.badlogic.gdx.assets.loaders.resolvers.ClasspathFileHandleResolver;
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.I18NBundle;
import com.zqll.gdx.starter.assets.font.FontGenerator;
import com.zqll.gdx.starter.assets.ui.FreeTypeSkinLoader;

import java.util.Locale;

/**
 * StarterAssets：统一的资源加载入口，尽量少概念、用法简洁。
 * <p>
 * - 自动检测 Internal/ClassPath 资源模式；
 * <p>
 * - 一次性加载皮肤与国际化；
 * <p>
 * - 简单获取中文友好字体（运行时 FreeType 生成）；
 */
public final class StarterAssets {

    private static AssetManager assetManager;
    private static boolean useClasspath;
    private static boolean initialized;

    private static Skin skin;
    private static I18NBundle i18n;
    private static FontGenerator fontGen;

    private StarterAssets() {
    }

    /**
     * 初始化并自动选择资源解析器（Internal 或 Classpath）。
     */
    public static void init() {
        StarterAssets.init(AssetPaths.FONT_MAPLE_MONO_SC, 16);
    }

    /**
     * 使用指定字体路径初始化（阻塞），自动处理 Internal/Classpath 两种资源模式。
     * 建议传入相对路径：
     * - Classpath 模式：传入 "fonts/xxx.ttf" 或 "assets/fonts/xxx.ttf"；
     * - Internal 模式：传入 "fonts/xxx.ttf"（如你项目 assets/ 下）。
     */
    public static void init(String preferredFontPath) {
        StarterAssets.init(preferredFontPath, 16);
    }

    /**
     * 使用指定字体路径与默认字号初始化，自动处理 Internal/Classpath 两种资源模式。
     */
    public static void init(String preferredFontPath, int defaultSize) {
        if (initialized) return;

        useClasspath = detectClasspathMode();
        FileHandleResolver resolver = useClasspath ? new ClasspathFileHandleResolver() : new InternalFileHandleResolver();
        assetManager = new AssetManager(resolver);

        fontGen = new FontGenerator();
        String effective;
        if (preferredFontPath == null || preferredFontPath.isEmpty()) {
            effective = useClasspath ? AssetPaths.classpath(AssetPaths.FONT_MAPLE_MONO_SC) : AssetPaths.FONT_MAPLE_MONO_SC;
        } else {
            if (useClasspath) {
                // Classpath 资源需以 "assets/" 前缀或通过 AssetPaths.classpath 包装
                effective = preferredFontPath.startsWith("assets/") ? preferredFontPath : AssetPaths.classpath(preferredFontPath);
            } else {
                // Internal 模式不应包含 "assets/" 前缀
                effective = preferredFontPath.startsWith("assets/") ? preferredFontPath.substring("assets/".length()) : preferredFontPath;
            }
        }

        try {
            fontGen.initialize(effective, defaultSize);
        } catch (Exception e) {
            String fallback = useClasspath ? AssetPaths.classpath(AssetPaths.FONT_NOTO_MONO_CJK) : AssetPaths.FONT_NOTO_MONO_CJK;
            fontGen.initialize(fallback, defaultSize);
        }

        initialized = true;
    }

    /**
     * 一次性加载皮肤与 i18n（阻塞式）。
     */
    public static void loadDefaults() {
        ensureInit();
        FileHandleResolver resolver = assetManager.getFileHandleResolver();

        // 皮肤（支持 FreeType 字体从 JSON）
        assetManager.setLoader(Skin.class, new FreeTypeSkinLoader(resolver));
        String skinJson = prefix(AssetPaths.UI_SKIN_JSON);
        assetManager.load(skinJson, Skin.class);

        // 国际化 bundle
        assetManager.setLoader(I18NBundle.class, new I18NBundleLoader(resolver));
        String i18nBase = prefix(AssetPaths.I18N_BUNDLE_BASE);
        I18NBundleLoader.I18NBundleParameter i18nParam = new I18NBundleLoader.I18NBundleParameter(Locale.getDefault());
        assetManager.load(i18nBase, I18NBundle.class, i18nParam);

        assetManager.finishLoading();

        skin = assetManager.get(skinJson, Skin.class);
        i18n = assetManager.get(i18nBase, I18NBundle.class);

        // 将默认字体加入皮肤（名称 default-font），以便直接使用
        if (skin != null) {
            if (!skin.has("default-font", com.badlogic.gdx.graphics.g2d.BitmapFont.class)) {
                com.badlogic.gdx.graphics.g2d.BitmapFont font = fontGen.generateFont(18);
                skin.add("default-font", font, com.badlogic.gdx.graphics.g2d.BitmapFont.class);
            }
        }
    }

    /**
     * 返回加载好的皮肤；若未加载会触发默认加载。
     */
    public static Skin getSkin() {
        ensureInit();
        if (skin == null) loadDefaults();
        return skin;
    }

    /**
     * 返回 i18n 文案；若未加载会触发默认加载。
     */
    public static I18NBundle getI18N() {
        ensureInit();
        if (i18n == null) loadDefaults();
        return i18n;
    }

    /**
     * 获取中文友好字体。
     */
    public static com.badlogic.gdx.graphics.g2d.BitmapFont font(int size) {
        ensureInit();
        return fontGen.generateFont(size);
    }

    /**
     * 获取指定颜色的中文友好字体。
     */
    public static com.badlogic.gdx.graphics.g2d.BitmapFont font(int size, Color color) {
        ensureInit();
        return fontGen.generateFont(size, color, false);
    }

    /**
     * 释放全部资源。
     */
    public static void dispose() {
        if (skin != null) skin.dispose();
        skin = null;
        i18n = null;
        if (assetManager != null) assetManager.dispose();
        assetManager = null;
        if (fontGen != null) fontGen.dispose();
        initialized = false;
    }

    private static boolean detectClasspathMode() {
        // 优先检测 internal 是否存在，否则回退到 classpath
        boolean internalSkinExists = Gdx.files.internal(AssetPaths.UI_SKIN_JSON).exists();
        if (internalSkinExists) return false;
        boolean classpathSkinExists = Gdx.files.classpath(AssetPaths.classpath(AssetPaths.UI_SKIN_JSON)).exists();
        return classpathSkinExists;
    }

    private static String prefix(String relative) {
        return useClasspath ? AssetPaths.classpath(relative) : relative;
    }

    private static void ensureInit() {
        if (!initialized) init();
    }

    /**
     * 暴露字体生成器，便于 FreeTypeSkin 等从 JSON 参数生成字体。
     */
    public static FontGenerator getFontGenerator() {
        ensureInit();
        return fontGen;
    }
}